﻿using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.TeamFoundation.Framework.Server;
using Microsoft.TeamFoundation.Server;
using Microsoft.TeamFoundation.Server.Core;
using Microsoft.TeamFoundation.VersionControl.Server;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.VisualStudio.Services.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace CodePlex.TfsPluginSuite.Helper
{
    public sealed class TfsHelper : IDisposable
    {
        private TeamFoundationRequestContext requestContext;
        private CheckinNotification notification;
        private TfsTeamProjectCollection tfsTeamProjectCollection;

        public TfsHelper(TeamFoundationRequestContext requestContext, CheckinNotification notification)
        {
            this.requestContext = requestContext;
            this.notification = notification;
        }

        #region WorkItemStore

        public NodeInfo GetIterationInfo(WorkItem workItem)
        {
            Node iterationNode = workItem.Project.FindNodeInSubTree(workItem.IterationId);
            var commonStructureService = (ICommonStructureService)GetTeamProjectCollection().GetService(typeof(ICommonStructureService));
            return commonStructureService.GetNode(iterationNode.Uri.ToString());
        }

        public WorkItem GetWorkItem(int workItemId)
        {
            var workItemStore = GetTeamProjectCollection().GetService<WorkItemStore>();
            return workItemStore.GetWorkItem(workItemId);
        }

        public int GetWorkItemQueryResultCount(string wiq)
        {
            var workItemStore = GetTeamProjectCollection().GetService<WorkItemStore>();
            var query = new Query(workItemStore, ResolveWiqMacros(wiq));
            return query.RunCountQuery();
        }

        #endregion

        #region Version Control

        public IEnumerable<PendingChange> GetPendingChanges()
        {
            var vcs = requestContext.GetService<TeamFoundationVersionControlService>();
            var submittedItems = notification.GetSubmittedItems(requestContext).Select(a => new ItemSpec(a, RecursionType.None)).ToArray();
            return vcs.QueryPendingChangesForWorkspace(requestContext, notification.WorkspaceName, notification.WorkspaceOwner.UniqueName, submittedItems, false, submittedItems.Length, null, true).CurrentEnumerable<PendingChange>();
        }

        #endregion

        #region Identities

        public bool IsInGroup(string groupName, IdentityDescriptor member)
        {
            var ims = requestContext.GetService<TeamFoundationIdentityService>();
            var group = ims.ReadIdentity(requestContext, IdentitySearchFactor.DisplayName, groupName);
            return ims.IsMember(requestContext, group.Descriptor, member);
        }

        #endregion

        #region private methods

        private Uri GetTFSUri()
        {
            var locationService = this.requestContext.GetService<TeamFoundationLocationService>();
            return new Uri(locationService.GetServerAccessMapping(requestContext).AccessPoint + "/" + requestContext.ServiceHost.Name);
        }

        private TfsTeamProjectCollection GetTeamProjectCollection()
        {
            if (tfsTeamProjectCollection == null)
            {
                tfsTeamProjectCollection = new TfsTeamProjectCollection(GetTFSUri());
            }
            return tfsTeamProjectCollection;
        }

        private string ResolveWiqMacros(string wiq)
        {
            var associatedWorkItems = notification.NotificationInfo.WorkItemInfo;
            string resolvedWiq = wiq;

            if (Regex.IsMatch(wiq, "@AssociatedWorkItems", RegexOptions.IgnoreCase))
            {
                var workItemIds = associatedWorkItems.AsEnumerable().Select(wiInfo => wiInfo.Id);
                var formattedWorkItemIds = string.Format("({0})", String.Join(",", workItemIds));
                resolvedWiq = Regex.Replace(resolvedWiq, "@AssociatedWorkItems", formattedWorkItemIds, RegexOptions.IgnoreCase);
            }

            if (Regex.IsMatch(wiq, "@Me", RegexOptions.IgnoreCase))
            {
                string userDisplayNameWithQuotes = "'" + GetUserDisplayName() + "'";
                resolvedWiq = Regex.Replace(resolvedWiq, "@Me", userDisplayNameWithQuotes, RegexOptions.IgnoreCase);
            }

            return resolvedWiq;
        }

        private string GetUserDisplayName()
        {
            var ims = requestContext.GetService<TeamFoundationIdentityService>();
            var user = ims.ReadIdentity(requestContext, IdentitySearchFactor.AccountName, requestContext.DomainUserName);
            return user.DisplayName;
        }

        #endregion

        #region IDisposable

        public void Dispose()
        {
            if (tfsTeamProjectCollection != null)
            {
                tfsTeamProjectCollection.Dispose();
            }
        }

        #endregion

    }
}
